home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume12 / cnews / part12 < prev    next >
Encoding:
Internet Message Format  |  1987-10-22  |  40.0 KB

  1. Subject:  v12i037:  C News alpha release, Part12/14
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry (Henry Spencer)
  7. Posting-number: Volume 12, Issue 37
  8. Archive-name: cnews/part12
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 12 (of 14)."
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'libc/strings/tester.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'libc/strings/tester.c'\"
  20. else
  21. echo shar: Extracting \"'libc/strings/tester.c'\" \(19922 characters\)
  22. sed "s/^X//" >'libc/strings/tester.c' <<'END_OF_FILE'
  23. X/*
  24. X * Test program for string(3) routines.
  25. X * 
  26. X * Note that at least one Bell Labs implementation of the string
  27. X * routines flunks a couple of these tests -- the ones which test
  28. X * behavior on "negative" characters.
  29. X */
  30. X
  31. X#include <stdio.h>
  32. X#include <string.h>
  33. X
  34. X#define    STREQ(a, b)    (strcmp((a), (b)) == 0)
  35. X
  36. Xchar *it = "<UNSET>";        /* Routine name for message routines. */
  37. Xint waserror = 0;        /* For exit status. */
  38. X
  39. Xchar uctest[] = "\004\203";    /* For testing signedness of chars. */
  40. Xint charsigned;            /* Result. */
  41. X
  42. X/*
  43. X - check - complain if condition is not true
  44. X */
  45. Xvoid
  46. Xcheck(thing, number)
  47. Xint thing;
  48. Xint number;            /* Test number for error message. */
  49. X{
  50. X    if (!thing) {
  51. X        printf("%s flunked test %d\n", it, number);
  52. X        waserror = 1;
  53. X    }
  54. X}
  55. X
  56. X/*
  57. X - equal - complain if first two args don't strcmp as equal
  58. X */
  59. Xvoid
  60. Xequal(a, b, number)
  61. Xchar *a;
  62. Xchar *b;
  63. Xint number;            /* Test number for error message. */
  64. X{
  65. X    check(a != NULL && b != NULL && STREQ(a, b), number);
  66. X}
  67. X
  68. Xchar one[50];
  69. Xchar two[50];
  70. X
  71. X#ifdef UNIXERR
  72. X#define ERR 1
  73. X#endif
  74. X#ifdef BERKERR
  75. X#define ERR 1
  76. X#endif
  77. X#ifdef ERR
  78. Xint f;
  79. Xextern char *sys_errlist[];
  80. Xextern int sys_nerr;
  81. Xextern int errno;
  82. X#endif
  83. X
  84. X/* ARGSUSED */
  85. Xmain(argc, argv)
  86. Xint argc;
  87. Xchar *argv[];
  88. X{
  89. X    /*
  90. X     * First, establish whether chars are signed.
  91. X     */
  92. X    if (uctest[0] < uctest[1])
  93. X        charsigned = 0;
  94. X    else
  95. X        charsigned = 1;
  96. X
  97. X    /*
  98. X     * Then, do the rest of the work.  Split into two functions because
  99. X     * some compilers get unhappy about a single immense function.
  100. X     */
  101. X    first();
  102. X    second();
  103. X
  104. X    exit((waserror) ? 1 : 0);
  105. X}
  106. X
  107. Xfirst()
  108. X{
  109. X    /*
  110. X     * Test strcmp first because we use it to test other things.
  111. X     */
  112. X    it = "strcmp";
  113. X    check(strcmp("", "") == 0, 1);        /* Trivial case. */
  114. X    check(strcmp("a", "a") == 0, 2);    /* Identity. */
  115. X    check(strcmp("abc", "abc") == 0, 3);    /* Multicharacter. */
  116. X    check(strcmp("abc", "abcd") < 0, 4);    /* Length mismatches. */
  117. X    check(strcmp("abcd", "abc") > 0, 5);
  118. X    check(strcmp("abcd", "abce") < 0, 6);    /* Honest miscompares. */
  119. X    check(strcmp("abce", "abcd") > 0, 7);
  120. X    check(strcmp("a\203", "a") > 0, 8);    /* Tricky if char signed. */
  121. X    if (charsigned)                /* Sign-bit comparison. */
  122. X        check(strcmp("a\203", "a\003") < 0, 9);
  123. X    else
  124. X        check(strcmp("a\203", "a\003") > 0, 9);
  125. X
  126. X    /*
  127. X     * Test strcpy next because we need it to set up other tests.
  128. X     */
  129. X    it = "strcpy";
  130. X    check(strcpy(one, "abcd") == one, 1);    /* Returned value. */
  131. X    equal(one, "abcd", 2);            /* Basic test. */
  132. X
  133. X    (void) strcpy(one, "x");
  134. X    equal(one, "x", 3);            /* Writeover. */
  135. X    equal(one+2, "cd", 4);            /* Wrote too much? */
  136. X
  137. X    (void) strcpy(two, "hi there");
  138. X    (void) strcpy(one, two);
  139. X    equal(one, "hi there", 5);        /* Basic test encore. */
  140. X    equal(two, "hi there", 6);        /* Stomped on source? */
  141. X
  142. X    (void) strcpy(one, "");
  143. X    equal(one, "", 7);            /* Boundary condition. */
  144. X
  145. X    /*
  146. X     * strcat
  147. X     */
  148. X    it = "strcat";
  149. X    (void) strcpy(one, "ijk");
  150. X    check(strcat(one, "lmn") == one, 1);    /* Returned value. */
  151. X    equal(one, "ijklmn", 2);        /* Basic test. */
  152. X
  153. X    (void) strcpy(one, "x");
  154. X    (void) strcat(one, "yz");
  155. X    equal(one, "xyz", 3);            /* Writeover. */
  156. X    equal(one+4, "mn", 4);            /* Wrote too much? */
  157. X
  158. X    (void) strcpy(one, "gh");
  159. X    (void) strcpy(two, "ef");
  160. X    (void) strcat(one, two);
  161. X    equal(one, "ghef", 5);            /* Basic test encore. */
  162. X    equal(two, "ef", 6);            /* Stomped on source? */
  163. X
  164. X    (void) strcpy(one, "");
  165. X    (void) strcat(one, "");
  166. X    equal(one, "", 7);            /* Boundary conditions. */
  167. X    (void) strcpy(one, "ab");
  168. X    (void) strcat(one, "");
  169. X    equal(one, "ab", 8);
  170. X    (void) strcpy(one, "");
  171. X    (void) strcat(one, "cd");
  172. X    equal(one, "cd", 9);
  173. X
  174. X    /*
  175. X     * strncat - first test it as strcat, with big counts, then
  176. X     * test the count mechanism.
  177. X     */
  178. X    it = "strncat";
  179. X    (void) strcpy(one, "ijk");
  180. X    check(strncat(one, "lmn", 99) == one, 1);    /* Returned value. */
  181. X    equal(one, "ijklmn", 2);        /* Basic test. */
  182. X
  183. X    (void) strcpy(one, "x");
  184. X    (void) strncat(one, "yz", 99);
  185. X    equal(one, "xyz", 3);            /* Writeover. */
  186. X    equal(one+4, "mn", 4);            /* Wrote too much? */
  187. X
  188. X    (void) strcpy(one, "gh");
  189. X    (void) strcpy(two, "ef");
  190. X    (void) strncat(one, two, 99);
  191. X    equal(one, "ghef", 5);            /* Basic test encore. */
  192. X    equal(two, "ef", 6);            /* Stomped on source? */
  193. X
  194. X    (void) strcpy(one, "");
  195. X    (void) strncat(one, "", 99);
  196. X    equal(one, "", 7);            /* Boundary conditions. */
  197. X    (void) strcpy(one, "ab");
  198. X    (void) strncat(one, "", 99);
  199. X    equal(one, "ab", 8);
  200. X    (void) strcpy(one, "");
  201. X    (void) strncat(one, "cd", 99);
  202. X    equal(one, "cd", 9);
  203. X
  204. X    (void) strcpy(one, "ab");
  205. X    (void) strncat(one, "cdef", 2);
  206. X    equal(one, "abcd", 10);            /* Count-limited. */
  207. X
  208. X    (void) strncat(one, "gh", 0);
  209. X    equal(one, "abcd", 11);            /* Zero count. */
  210. X
  211. X    (void) strncat(one, "gh", 2);
  212. X    equal(one, "abcdgh", 12);        /* Count and length equal. */
  213. X
  214. X    /*
  215. X     * strncmp - first test as strcmp with big counts, then test
  216. X     * count code.
  217. X     */
  218. X    it = "strncmp";
  219. X    check(strncmp("", "", 99) == 0, 1);    /* Trivial case. */
  220. X    check(strncmp("a", "a", 99) == 0, 2);    /* Identity. */
  221. X    check(strncmp("abc", "abc", 99) == 0, 3);    /* Multicharacter. */
  222. X    check(strncmp("abc", "abcd", 99) < 0, 4);    /* Length unequal. */
  223. X    check(strncmp("abcd", "abc", 99) > 0, 5);
  224. X    check(strncmp("abcd", "abce", 99) < 0, 6);    /* Honestly unequal. */
  225. X    check(strncmp("abce", "abcd", 99) > 0, 7);
  226. X    check(strncmp("a\203", "a", 2) > 0, 8);    /* Tricky if '\203' < 0 */
  227. X    if (charsigned)                /* Sign-bit comparison. */
  228. X        check(strncmp("a\203", "a\003", 2) < 0, 9);
  229. X    else
  230. X        check(strncmp("a\203", "a\003", 2) > 0, 9);
  231. X    check(strncmp("abce", "abcd", 3) == 0, 10);    /* Count limited. */
  232. X    check(strncmp("abce", "abc", 3) == 0, 11);    /* Count == length. */
  233. X    check(strncmp("abcd", "abce", 4) < 0, 12);    /* Nudging limit. */
  234. X    check(strncmp("abc", "def", 0) == 0, 13);    /* Zero count. */
  235. X
  236. X    /*
  237. X     * strncpy - testing is a bit different because of odd semantics
  238. X     */
  239. X    it = "strncpy";
  240. X    check(strncpy(one, "abc", 4) == one, 1);    /* Returned value. */
  241. X    equal(one, "abc", 2);            /* Did the copy go right? */
  242. X
  243. X    (void) strcpy(one, "abcdefgh");
  244. X    (void) strncpy(one, "xyz", 2);
  245. X    equal(one, "xycdefgh", 3);        /* Copy cut by count. */
  246. X
  247. X    (void) strcpy(one, "abcdefgh");
  248. X    (void) strncpy(one, "xyz", 3);        /* Copy cut just before NUL. */
  249. X    equal(one, "xyzdefgh", 4);
  250. X
  251. X    (void) strcpy(one, "abcdefgh");
  252. X    (void) strncpy(one, "xyz", 4);        /* Copy just includes NUL. */
  253. X    equal(one, "xyz", 5);
  254. X    equal(one+4, "efgh", 6);        /* Wrote too much? */
  255. X
  256. X    (void) strcpy(one, "abcdefgh");
  257. X    (void) strncpy(one, "xyz", 5);        /* Copy includes padding. */
  258. X    equal(one, "xyz", 7);
  259. X    equal(one+4, "", 8);
  260. X    equal(one+5, "fgh", 9);
  261. X
  262. X    (void) strcpy(one, "abc");
  263. X    (void) strncpy(one, "xyz", 0);        /* Zero-length copy. */
  264. X    equal(one, "abc", 10);    
  265. X
  266. X    (void) strncpy(one, "", 2);        /* Zero-length source. */
  267. X    equal(one, "", 11);
  268. X    equal(one+1, "", 12);    
  269. X    equal(one+2, "c", 13);
  270. X
  271. X    (void) strcpy(one, "hi there");
  272. X    (void) strncpy(two, one, 9);
  273. X    equal(two, "hi there", 14);        /* Just paranoia. */
  274. X    equal(one, "hi there", 15);        /* Stomped on source? */
  275. X
  276. X    /*
  277. X     * strlen
  278. X     */
  279. X    it = "strlen";
  280. X    check(strlen("") == 0, 1);        /* Empty. */
  281. X    check(strlen("a") == 1, 2);        /* Single char. */
  282. X    check(strlen("abcd") == 4, 3);        /* Multiple chars. */
  283. X
  284. X    /*
  285. X     * strchr
  286. X     */
  287. X    it = "strchr";
  288. X    check(strchr("abcd", 'z') == NULL, 1);    /* Not found. */
  289. X    (void) strcpy(one, "abcd");
  290. X    check(strchr(one, 'c') == one+2, 2);    /* Basic test. */
  291. X    check(strchr(one, 'd') == one+3, 3);    /* End of string. */
  292. X    check(strchr(one, 'a') == one, 4);    /* Beginning. */
  293. X    check(strchr(one, '\0') == one+4, 5);    /* Finding NUL. */
  294. X    (void) strcpy(one, "ababa");
  295. X    check(strchr(one, 'b') == one+1, 6);    /* Finding first. */
  296. X    (void) strcpy(one, "");
  297. X    check(strchr(one, 'b') == NULL, 7);    /* Empty string. */
  298. X    check(strchr(one, '\0') == one, 8);    /* NUL in empty string. */
  299. X
  300. X    /*
  301. X     * index - just like strchr
  302. X     */
  303. X    it = "index";
  304. X    check(index("abcd", 'z') == NULL, 1);    /* Not found. */
  305. X    (void) strcpy(one, "abcd");
  306. X    check(index(one, 'c') == one+2, 2);    /* Basic test. */
  307. X    check(index(one, 'd') == one+3, 3);    /* End of string. */
  308. X    check(index(one, 'a') == one, 4);    /* Beginning. */
  309. X    check(index(one, '\0') == one+4, 5);    /* Finding NUL. */
  310. X    (void) strcpy(one, "ababa");
  311. X    check(index(one, 'b') == one+1, 6);    /* Finding first. */
  312. X    (void) strcpy(one, "");
  313. X    check(index(one, 'b') == NULL, 7);    /* Empty string. */
  314. X    check(index(one, '\0') == one, 8);    /* NUL in empty string. */
  315. X
  316. X    /*
  317. X     * strrchr
  318. X     */
  319. X    it = "strrchr";
  320. X    check(strrchr("abcd", 'z') == NULL, 1);    /* Not found. */
  321. X    (void) strcpy(one, "abcd");
  322. X    check(strrchr(one, 'c') == one+2, 2);    /* Basic test. */
  323. X    check(strrchr(one, 'd') == one+3, 3);    /* End of string. */
  324. X    check(strrchr(one, 'a') == one, 4);    /* Beginning. */
  325. X    check(strrchr(one, '\0') == one+4, 5);    /* Finding NUL. */
  326. X    (void) strcpy(one, "ababa");
  327. X    check(strrchr(one, 'b') == one+3, 6);    /* Finding last. */
  328. X    (void) strcpy(one, "");
  329. X    check(strrchr(one, 'b') == NULL, 7);    /* Empty string. */
  330. X    check(strrchr(one, '\0') == one, 8);    /* NUL in empty string. */
  331. X
  332. X    /*
  333. X     * rindex - just like strrchr
  334. X     */
  335. X    it = "rindex";
  336. X    check(rindex("abcd", 'z') == NULL, 1);    /* Not found. */
  337. X    (void) strcpy(one, "abcd");
  338. X    check(rindex(one, 'c') == one+2, 2);    /* Basic test. */
  339. X    check(rindex(one, 'd') == one+3, 3);    /* End of string. */
  340. X    check(rindex(one, 'a') == one, 4);    /* Beginning. */
  341. X    check(rindex(one, '\0') == one+4, 5);    /* Finding NUL. */
  342. X    (void) strcpy(one, "ababa");
  343. X    check(rindex(one, 'b') == one+3, 6);    /* Finding last. */
  344. X    (void) strcpy(one, "");
  345. X    check(rindex(one, 'b') == NULL, 7);    /* Empty string. */
  346. X    check(rindex(one, '\0') == one, 8);    /* NUL in empty string. */
  347. X}
  348. X
  349. Xsecond()
  350. X{
  351. X    /*
  352. X     * strpbrk - somewhat like strchr
  353. X     */
  354. X    it = "strpbrk";
  355. X    check(strpbrk("abcd", "z") == NULL, 1);    /* Not found. */
  356. X    (void) strcpy(one, "abcd");
  357. X    check(strpbrk(one, "c") == one+2, 2);    /* Basic test. */
  358. X    check(strpbrk(one, "d") == one+3, 3);    /* End of string. */
  359. X    check(strpbrk(one, "a") == one, 4);    /* Beginning. */
  360. X    check(strpbrk(one, "") == NULL, 5);    /* Empty search list. */
  361. X    check(strpbrk(one, "cb") == one+1, 6);    /* Multiple search. */
  362. X    (void) strcpy(one, "abcabdea");
  363. X    check(strpbrk(one, "b") == one+1, 7);    /* Finding first. */
  364. X    check(strpbrk(one, "cb") == one+1, 8);    /* With multiple search. */
  365. X    check(strpbrk(one, "db") == one+1, 9);    /* Another variant. */
  366. X    (void) strcpy(one, "");
  367. X    check(strpbrk(one, "bc") == NULL, 10);    /* Empty string. */
  368. X    check(strpbrk(one, "") == NULL, 11);    /* Both strings empty. */
  369. X
  370. X    /*
  371. X     * strstr - somewhat like strchr
  372. X     */
  373. X    it = "strstr";
  374. X    check(strstr("abcd", "z") == NULL, 1);    /* Not found. */
  375. X    check(strstr("abcd", "abx") == NULL, 2);    /* Dead end. */
  376. X    (void) strcpy(one, "abcd");
  377. X    check(strstr(one, "c") == one+2, 3);    /* Basic test. */
  378. X    check(strstr(one, "bc") == one+1, 4);    /* Multichar. */
  379. X    check(strstr(one, "d") == one+3, 5);    /* End of string. */
  380. X    check(strstr(one, "cd") == one+2, 6);    /* Tail of string. */
  381. X    check(strstr(one, "abc") == one, 7);    /* Beginning. */
  382. X    check(strstr(one, "abcd") == one, 8);    /* Exact match. */
  383. X    check(strstr(one, "abcde") == NULL, 9);    /* Too long. */
  384. X    check(strstr(one, "de") == NULL, 10);    /* Past end. */
  385. X    check(strstr(one, "") == one+4, 11);    /* Finding empty. */
  386. X    (void) strcpy(one, "ababa");
  387. X    check(strstr(one, "ba") == one+1, 12);    /* Finding first. */
  388. X    (void) strcpy(one, "");
  389. X    check(strstr(one, "b") == NULL, 13);    /* Empty string. */
  390. X    check(strstr(one, "") == one, 14);    /* Empty in empty string. */
  391. X    (void) strcpy(one, "bcbca");
  392. X    check(strstr(one, "bca") == one+2, 15);    /* False start. */
  393. X    (void) strcpy(one, "bbbcabbca");
  394. X    check(strstr(one, "bbca") == one+1, 16);    /* With overlap. */
  395. X
  396. X    /*
  397. X     * strspn
  398. X     */
  399. X    it = "strspn";
  400. X    check(strspn("abcba", "abc") == 5, 1);    /* Whole string. */
  401. X    check(strspn("abcba", "ab") == 2, 2);    /* Partial. */
  402. X    check(strspn("abc", "qx") == 0, 3);    /* None. */
  403. X    check(strspn("", "ab") == 0, 4);    /* Null string. */
  404. X    check(strspn("abc", "") == 0, 5);    /* Null search list. */
  405. X
  406. X    /*
  407. X     * strcspn
  408. X     */
  409. X    it = "strcspn";
  410. X    check(strcspn("abcba", "qx") == 5, 1);    /* Whole string. */
  411. X    check(strcspn("abcba", "cx") == 2, 2);    /* Partial. */
  412. X    check(strcspn("abc", "abc") == 0, 3);    /* None. */
  413. X    check(strcspn("", "ab") == 0, 4);    /* Null string. */
  414. X    check(strcspn("abc", "") == 3, 5);    /* Null search list. */
  415. X
  416. X    /*
  417. X     * strtok - the hard one
  418. X     */
  419. X    it = "strtok";
  420. X    (void) strcpy(one, "first, second, third");
  421. X    equal(strtok(one, ", "), "first", 1);    /* Basic test. */
  422. X    equal(one, "first", 2);
  423. X    equal(strtok((char *)NULL, ", "), "second", 3);
  424. X    equal(strtok((char *)NULL, ", "), "third", 4);
  425. X    check(strtok((char *)NULL, ", ") == NULL, 5);
  426. X    (void) strcpy(one, ", first, ");
  427. X    equal(strtok(one, ", "), "first", 6);    /* Extra delims, 1 tok. */
  428. X    check(strtok((char *)NULL, ", ") == NULL, 7);
  429. X    (void) strcpy(one, "1a, 1b; 2a, 2b");
  430. X    equal(strtok(one, ", "), "1a", 8);    /* Changing delim lists. */
  431. X    equal(strtok((char *)NULL, "; "), "1b", 9);
  432. X    equal(strtok((char *)NULL, ", "), "2a", 10);
  433. X    (void) strcpy(two, "x-y");
  434. X    equal(strtok(two, "-"), "x", 11);    /* New string before done. */
  435. X    equal(strtok((char *)NULL, "-"), "y", 12);
  436. X    check(strtok((char *)NULL, "-") == NULL, 13);
  437. X    (void) strcpy(one, "a,b, c,, ,d");
  438. X    equal(strtok(one, ", "), "a", 14);    /* Different separators. */
  439. X    equal(strtok((char *)NULL, ", "), "b", 15);
  440. X    equal(strtok((char *)NULL, " ,"), "c", 16);    /* Permute list too. */
  441. X    equal(strtok((char *)NULL, " ,"), "d", 17);
  442. X    check(strtok((char *)NULL, ", ") == NULL, 18);
  443. X    check(strtok((char *)NULL, ", ") == NULL, 19);    /* Persistence. */
  444. X    (void) strcpy(one, ", ");
  445. X    check(strtok(one, ", ") == NULL, 20);    /* No tokens. */
  446. X    (void) strcpy(one, "");
  447. X    check(strtok(one, ", ") == NULL, 21);    /* Empty string. */
  448. X    (void) strcpy(one, "abc");
  449. X    equal(strtok(one, ", "), "abc", 22);    /* No delimiters. */
  450. X    check(strtok((char *)NULL, ", ") == NULL, 23);
  451. X    (void) strcpy(one, "abc");
  452. X    equal(strtok(one, ""), "abc", 24);    /* Empty delimiter list. */
  453. X    check(strtok((char *)NULL, "") == NULL, 25);
  454. X    (void) strcpy(one, "abcdefgh");
  455. X    (void) strcpy(one, "a,b,c");
  456. X    equal(strtok(one, ","), "a", 26);    /* Basics again... */
  457. X    equal(strtok((char *)NULL, ","), "b", 27);
  458. X    equal(strtok((char *)NULL, ","), "c", 28);
  459. X    check(strtok((char *)NULL, ",") == NULL, 29);
  460. X    equal(one+6, "gh", 30);            /* Stomped past end? */
  461. X    equal(one, "a", 31);            /* Stomped old tokens? */
  462. X    equal(one+2, "b", 32);
  463. X    equal(one+4, "c", 33);
  464. X
  465. X    /*
  466. X     * memcmp
  467. X     */
  468. X    it = "memcmp";
  469. X    check(memcmp("a", "a", 1) == 0, 1);    /* Identity. */
  470. X    check(memcmp("abc", "abc", 3) == 0, 2);    /* Multicharacter. */
  471. X    check(memcmp("abcd", "abce", 4) < 0, 3);    /* Honestly unequal. */
  472. X    check(memcmp("abce", "abcd", 4) > 0, 4);
  473. X    check(memcmp("alph", "beta", 4) < 0, 5);
  474. X    if (charsigned)                /* Sign-bit comparison. */
  475. X        check(memcmp("a\203", "a\003", 2) < 0, 6);
  476. X    else
  477. X        check(memcmp("a\203", "a\003", 2) > 0, 6);
  478. X    check(memcmp("abce", "abcd", 3) == 0, 7);    /* Count limited. */
  479. X    check(memcmp("abc", "def", 0) == 0, 8);    /* Zero count. */
  480. X
  481. X    /*
  482. X     * memchr
  483. X     */
  484. X    it = "memchr";
  485. X    check(memchr("abcd", 'z', 4) == NULL, 1);    /* Not found. */
  486. X    (void) strcpy(one, "abcd");
  487. X    check(memchr(one, 'c', 4) == one+2, 2);    /* Basic test. */
  488. X    check(memchr(one, 'd', 4) == one+3, 3);    /* End of string. */
  489. X    check(memchr(one, 'a', 4) == one, 4);    /* Beginning. */
  490. X    check(memchr(one, '\0', 5) == one+4, 5);    /* Finding NUL. */
  491. X    (void) strcpy(one, "ababa");
  492. X    check(memchr(one, 'b', 5) == one+1, 6);    /* Finding first. */
  493. X    check(memchr(one, 'b', 0) == NULL, 7);    /* Zero count. */
  494. X    check(memchr(one, 'a', 1) == one, 8);    /* Singleton case. */
  495. X    (void) strcpy(one, "a\203b");
  496. X    check(memchr(one, 0203, 3) == one+1, 9);    /* Unsignedness. */
  497. X
  498. X    /*
  499. X     * memcpy
  500. X     *
  501. X     * Note that X3J11 says memcpy must work regardless of overlap.
  502. X     * The SVID says it might fail.
  503. X     */
  504. X    it = "memcpy";
  505. X    check(memcpy(one, "abc", 4) == one, 1);    /* Returned value. */
  506. X    equal(one, "abc", 2);            /* Did the copy go right? */
  507. X
  508. X    (void) strcpy(one, "abcdefgh");
  509. X    (void) memcpy(one+1, "xyz", 2);
  510. X    equal(one, "axydefgh", 3);        /* Basic test. */
  511. X
  512. X    (void) strcpy(one, "abc");
  513. X    (void) memcpy(one, "xyz", 0);
  514. X    equal(one, "abc", 4);            /* Zero-length copy. */
  515. X
  516. X    (void) strcpy(one, "hi there");
  517. X    (void) strcpy(two, "foo");
  518. X    (void) memcpy(two, one, 9);
  519. X    equal(two, "hi there", 5);        /* Just paranoia. */
  520. X    equal(one, "hi there", 6);        /* Stomped on source? */
  521. X
  522. X    (void) strcpy(one, "abcdefgh");
  523. X    (void) memcpy(one+1, one, 9);
  524. X    equal(one, "aabcdefgh", 7);        /* Overlap, right-to-left. */
  525. X
  526. X    (void) strcpy(one, "abcdefgh");
  527. X    (void) memcpy(one+1, one+2, 7);
  528. X    equal(one, "acdefgh", 8);        /* Overlap, left-to-right. */
  529. X
  530. X    (void) strcpy(one, "abcdefgh");
  531. X    (void) memcpy(one, one, 9);
  532. X    equal(one, "abcdefgh", 9);        /* 100% overlap. */
  533. X
  534. X    /*
  535. X     * memccpy - first test like memcpy, then the search part
  536. X     *
  537. X     * The SVID, the only place where memccpy is mentioned, says
  538. X     * overlap might fail, so we don't try it.  Besides, it's hard
  539. X     * to see the rationale for a non-left-to-right memccpy.
  540. X     */
  541. X    it = "memccpy";
  542. X    check(memccpy(one, "abc", 'q', 4) == NULL, 1);    /* Returned value. */
  543. X    equal(one, "abc", 2);            /* Did the copy go right? */
  544. X
  545. X    (void) strcpy(one, "abcdefgh");
  546. X    (void) memccpy(one+1, "xyz", 'q', 2);
  547. X    equal(one, "axydefgh", 3);        /* Basic test. */
  548. X
  549. X    (void) strcpy(one, "abc");
  550. X    (void) memccpy(one, "xyz", 'q', 0);
  551. X    equal(one, "abc", 4);            /* Zero-length copy. */
  552. X
  553. X    (void) strcpy(one, "hi there");
  554. X    (void) strcpy(two, "foo");
  555. X    (void) memccpy(two, one, 'q', 9);
  556. X    equal(two, "hi there", 5);        /* Just paranoia. */
  557. X    equal(one, "hi there", 6);        /* Stomped on source? */
  558. X
  559. X    (void) strcpy(one, "abcdefgh");
  560. X    (void) strcpy(two, "horsefeathers");
  561. X    check(memccpy(two, one, 'f', 9) == two+6, 7);    /* Returned value. */
  562. X    equal(one, "abcdefgh", 8);        /* Source intact? */
  563. X    equal(two, "abcdefeathers", 9);        /* Copy correct? */
  564. X
  565. X    (void) strcpy(one, "abcd");
  566. X    (void) strcpy(two, "bumblebee");
  567. X    check(memccpy(two, one, 'a', 4) == two+1, 10);    /* First char. */
  568. X    equal(two, "aumblebee", 11);
  569. X    check(memccpy(two, one, 'd', 4) == two+4, 12);    /* Last char. */
  570. X    equal(two, "abcdlebee", 13);
  571. X    (void) strcpy(one, "xyz");
  572. X    check(memccpy(two, one, 'x', 1) == two+1, 14);    /* Singleton. */
  573. X    equal(two, "xbcdlebee", 15);
  574. X
  575. X    /*
  576. X     * memset
  577. X     */
  578. X    it = "memset";
  579. X    (void) strcpy(one, "abcdefgh");
  580. X    check(memset(one+1, 'x', 3) == one+1, 1);    /* Return value. */
  581. X    equal(one, "axxxefgh", 2);        /* Basic test. */
  582. X
  583. X    (void) memset(one+2, 'y', 0);
  584. X    equal(one, "axxxefgh", 3);        /* Zero-length set. */
  585. X
  586. X    (void) memset(one+5, 0, 1);
  587. X    equal(one, "axxxe", 4);            /* Zero fill. */
  588. X    equal(one+6, "gh", 5);            /* And the leftover. */
  589. X
  590. X    (void) memset(one+2, 010045, 1);
  591. X    equal(one, "ax\045xe", 6);        /* Unsigned char convert. */
  592. X
  593. X    /*
  594. X     * bcopy - much like memcpy
  595. X     *
  596. X     * Berklix manual is silent about overlap, so don't test it.
  597. X     */
  598. X    it = "bcopy";
  599. X    (void) bcopy("abc", one, 4);
  600. X    equal(one, "abc", 1);            /* Simple copy. */
  601. X
  602. X    (void) strcpy(one, "abcdefgh");
  603. X    (void) bcopy("xyz", one+1, 2);
  604. X    equal(one, "axydefgh", 2);        /* Basic test. */
  605. X
  606. X    (void) strcpy(one, "abc");
  607. X    (void) bcopy("xyz", one, 0);
  608. X    equal(one, "abc", 3);            /* Zero-length copy. */
  609. X
  610. X    (void) strcpy(one, "hi there");
  611. X    (void) strcpy(two, "foo");
  612. X    (void) bcopy(one, two, 9);
  613. X    equal(two, "hi there", 4);        /* Just paranoia. */
  614. X    equal(one, "hi there", 5);        /* Stomped on source? */
  615. X
  616. X    /*
  617. X     * bzero
  618. X     */
  619. X    it = "bzero";
  620. X    (void) strcpy(one, "abcdef");
  621. X    bzero(one+2, 2);
  622. X    equal(one, "ab", 1);            /* Basic test. */
  623. X    equal(one+3, "", 2);
  624. X    equal(one+4, "ef", 3);
  625. X
  626. X    (void) strcpy(one, "abcdef");
  627. X    bzero(one+2, 0);
  628. X    equal(one, "abcdef", 4);        /* Zero-length copy. */
  629. X
  630. X    /*
  631. X     * bcmp - somewhat like memcmp
  632. X     */
  633. X    it = "bcmp";
  634. X    check(bcmp("a", "a", 1) == 0, 1);    /* Identity. */
  635. X    check(bcmp("abc", "abc", 3) == 0, 2);    /* Multicharacter. */
  636. X    check(bcmp("abcd", "abce", 4) != 0, 3);    /* Honestly unequal. */
  637. X    check(bcmp("abce", "abcd", 4) != 0, 4);
  638. X    check(bcmp("alph", "beta", 4) != 0, 5);
  639. X    check(bcmp("abce", "abcd", 3) == 0, 6);    /* Count limited. */
  640. X    check(bcmp("abc", "def", 0) == 0, 8);    /* Zero count. */
  641. X
  642. X#ifdef ERR
  643. X    /*
  644. X     * strerror - VERY system-dependent
  645. X     */
  646. X    it = "strerror";
  647. X    f = open("/", 1);    /* Should always fail. */
  648. X    check(f < 0 && errno > 0 && errno < sys_nerr, 1);
  649. X    equal(strerror(errno), sys_errlist[errno], 2);
  650. X#ifdef UNIXERR
  651. X    equal(strerror(errno), "Is a directory", 3);
  652. X#endif
  653. X#ifdef BERKERR
  654. X    equal(strerror(errno), "Permission denied", 3);
  655. X#endif
  656. X#endif
  657. X}
  658. END_OF_FILE
  659. if test 19922 -ne `wc -c <'libc/strings/tester.c'`; then
  660.     echo shar: \"'libc/strings/tester.c'\" unpacked with wrong size!
  661. fi
  662. # end of 'libc/strings/tester.c'
  663. fi
  664. if test -f 'rnews/headers.c' -a "${1}" != "-c" ; then 
  665.   echo shar: Will not clobber existing file \"'rnews/headers.c'\"
  666. else
  667. echo shar: Extracting \"'rnews/headers.c'\" \(18247 characters\)
  668. sed "s/^X//" >'rnews/headers.c' <<'END_OF_FILE'
  669. X/*
  670. X * Usenet header parsing and generation (see RFCs 850 & 822;
  671. X *    for a second opinion, see The Hideous Name by Pike & Weinberger).
  672. X *
  673. X * Headers are parsed and modified and copied in one pass.
  674. X * Nevertheless, this file is split into two pieces: header parsing
  675. X * and remembering (aka eating) and header copying (aka munging).
  676. X * The split is marked and the two pieces are fairly independent.
  677. X *
  678. X * --- a quick tour of RFC 850 headers.  Hold on tight ---
  679. X *
  680. X * mandatory headers follow:
  681. X * Path: ucbvax!ukc!decvax!mcvax!ih*!kaist!mh*!ho*!brahms!nsu    # must prepend to
  682. X * From: whosit@brahms.b.uc.berkeley.edu.BERKELEY.EDU.uucp (Arthur ``Two-Sheds'' Jackson)
  683. X * Newsgroups: talk.philosophy.meaning.meaning
  684. X * Subject: Re: RE: re: rE: Orphaned Response - (nf)    # previously Title:
  685. X * Date: Sat, 25-Dec-86 04:05:06 GMT    # previously Posted:
  686. X * Message-ID: <unique@brahms.b.uc.berkeley.edu.BERKELEY.EDU.uucp> # previously Article-I.D.:
  687. X *
  688. X * optional headers follow:
  689. X * Relay-Version: C;utcs            # must replace; must be 1st (recently demoted)
  690. X * Posting-Version: version C alpha;site utcs.uucp    # (recently demoted)
  691. X * Date-Received: Sat, 25-Jan-87 12:34:56 GMT    # must replace or snuff * # previously Received:
  692. X * Organization: UCB society for arguing the meaning of meaning
  693. X * Distribution: ucb
  694. X * Sender: twosheds@arpa.b.uc.berkeley.edu.BERKELEY.EDU.uucp
  695. X * Followup-To: talk.tv.i.love.lucy
  696. X * Control: newgroup talk.philosophy.meaning.meaning.meaning    # magic; not for the uninitiated
  697. X * References: <345.wanker@isi-wankers.gov> <123.toadsexers@kcl-cs.uk>
  698. X * Reply-To: info-wankers@wankvax.b.uc.berkeley.edu.BERKELEY.EDU.uucp
  699. X * Expires: Sun, 31-dec-99 23:59:59 GMT
  700. X * Approved: kinsey@Uchicago.uucp        # the mark of the moderator
  701. X * Lines: 6766                    # redundant & pointless `wc -l`
  702. X *
  703. X * new headers not (yet?) in RFC850 follow:
  704. X * Summary: It was a dark and stormy night,    # retain
  705. X * Keywords: toadsexing, ether, tetanus        # retain
  706. X * Nf-*: transmitted via Notesviles        # might snuff
  707. X *
  708. X * abusive & silly non-RFC-850 headers follow:
  709. X * Sccs-Id: @(#) 5.2.vax.2.women.only  rob  3/5/83
  710. X * Hideous-Name: psuvax1!rhea::@brl.arpa:ucbvax!mit-mc%udel-relay.arpa@chris:umcp-cs::udel-relay%csnet-relay.vision.ubc.cdn
  711. X * Shoe-Size: 8
  712. X * Header-Questions-To: mark@pavo.cb.d.osg.cb.cbosgd.att.com.uucp
  713. X * Upas-To: eric@vax.b.uc.berkeley.edu.BERKELEY.EDU.uucp
  714. X * V9-Capable-Machines-To: utstat!geoff
  715. X * Uglix-Version: 5.3.vax.1.4/7/85.21:37:45.binary.only
  716. X *
  717. X * --- Ah well, it will only get worse. ---
  718. X */
  719. X
  720. X#include <stdio.h>
  721. X#include <ctype.h>
  722. X#include <sys/types.h>
  723. X#include "news.h"
  724. X#include "headers.h"
  725. X
  726. X#ifndef DEFDIST
  727. X#define DEFDIST "world"        /* default Distribution: */
  728. X#endif
  729. X#ifndef DEFMSGID
  730. X#define DEFMSGID "<wanker@isi-wankers.isi.usc.edu>"
  731. X#endif
  732. X
  733. X#define JUNK "junk"
  734. X#define ALL "all"
  735. X
  736. X#define OLDCNTRL "all.all.ctl"
  737. X
  738. X/*
  739. X * Derivation: 752 is a large header, 120 is approx. size of *-Version because
  740. X *    this rnews throws them away.  HDRMEMSIZ can be too small if
  741. X *    memory is tight and will only hurt performance.
  742. X */
  743. X#ifndef HDRMEMSIZ
  744. X#ifndef notdef
  745. X#define HDRMEMSIZ 8192            /* room for headers */
  746. X#else
  747. X#define HDRMEMSIZ (752-120)
  748. X#endif    /* notdef */
  749. X#endif    /* HDRMEMSIZ */
  750. X
  751. X    /* from here down are recognised in eatheaders() */
  752. Xstatic char ctlnm[] =    "Control:";
  753. Xstatic char distrnm[] =    "Distribution:";
  754. Xstatic char appnm[] =    "Approved:";
  755. Xstatic char subjnm[] =    "Subject:";
  756. Xstatic char msgnm[] =    "Message-ID:";
  757. Xstatic char artidnm[] =    "Article-I.D.:";    /* obsolete Message-ID: */
  758. X    /* from here down recognised by mungehdrs() */
  759. Xstatic char pathnm[] =    "Path:";        /* so we can extend it (damn) */
  760. Xstatic char ngsnm[] = "Newsgroups:";        /* to clone for Xref */
  761. X    /* down to here recognised by eatheaders() */
  762. Xstatic char xrefnm[] = "Xref:";            /* to *replace* Xref (damn!)*/
  763. X    /*
  764. X     * the following noxious headers are deleted because
  765. X     * neighbours still send them and they are big.
  766. X     * in an ideal world, they wouldn't be sent and thus
  767. X     * we wouldn't need to delete them.
  768. X     */
  769. X/* TODO: what about Posted: and Article-I.D.:? */
  770. Xstatic char datercvnm[] = "Date-Received:";    /* so we can snuff it */
  771. Xstatic char rcvnm[] = "Received:";        /* obsolete Date-Received: */
  772. Xstatic char rlyversnm[] = "Relay-Version:";    /* so we can snuff it */
  773. Xstatic char postversnm[] = "Posting-Version:";    /* so we can snuff it */
  774. X    /* down to here recognised by mungehdrs() */
  775. X
  776. X
  777. X/* TODO: permit multiples of hdrprs and hpsp */
  778. Xstruct hdrparsestate {
  779. X    char **prevvalp;    /* points at previous header value string */
  780. X    short prevhist;        /* previous line was a header line */
  781. X    short nextcont;        /* next line must be a header continuation */
  782. X    short newnextcont;    /* nextcont for next line, based on this line */
  783. X    char hdraccum[HDRMEMSIZ+MAXLINE];
  784. X    char *endlnp;        /* pointer to end of input buffer - 1 */
  785. X};
  786. Xstatic struct hdrparsestate hdrprs = { 0, NO, NO, 0 };    /* parser state */
  787. Xstatic struct hdrparsestate *hpsp = &hdrprs;
  788. X/* end of parser state */
  789. X
  790. X
  791. Xstatic int debug = NO;
  792. X
  793. X/* forward decls */
  794. Xchar *skipsp();
  795. X
  796. X/*
  797. X * --- common header code start ---
  798. X */
  799. X
  800. Xhdrdebug(state)
  801. Xint state;
  802. X{
  803. X    debug = state;
  804. X}
  805. X
  806. Xhdrinit(hdrs)            /* zero all pointers in hdrs */
  807. Xregister struct headers *hdrs;
  808. X{
  809. X    hdrs->h_subj = NULL;
  810. X    hdrs->h_ngs = NULL;
  811. X    hdrs->h_files[0] = '\0';
  812. X    hdrs->h_distr = NULL;
  813. X    hdrs->h_ctlcmd = NULL;
  814. X    hdrs->h_approved = NULL;
  815. X    hdrs->h_msgid = NULL;
  816. X    hdrs->h_artid = NULL;
  817. X    hdrs->h_expiry = NULL;
  818. X    hdrs->h_path = NULL;
  819. X    hdrs->h_tmpf[0] = '\0';
  820. X    hdrs->h_unlink = NO;
  821. X    hdrs->h_filed = NO;
  822. X    hdrs->h_xref = NO;
  823. X    hdrs->h_octlchked = NO;
  824. X    hdrs->h_oldctl = NO;
  825. X    hdrs->h_accum = NULL;
  826. X    hdrs->h_charswritten = 0;
  827. X}
  828. X
  829. Xstatic int
  830. Xoldctl(hdrs)            /* true iff ngs are OLDCNTRL (cache in hdrs) */
  831. Xregister struct headers *hdrs;
  832. X{
  833. X    if (!hdrs->h_octlchked) {        /* don't know yet */
  834. X        /* TODO: special case this, avoid ngmatch */
  835. X        hdrs->h_oldctl = ngmatch(OLDCNTRL, hdrs->h_ngs);
  836. X        hdrs->h_octlchked = YES;    /* now we know */
  837. X    }
  838. X    return hdrs->h_oldctl;
  839. X}
  840. X
  841. Xint
  842. Xhdrmutate(hdrs, buffer, tfp)        /* eat & munge headers */
  843. Xstruct headers *hdrs;
  844. Xchar *buffer;
  845. XFILE **tfp;
  846. X{
  847. X        eatheaders(hdrs, buffer);    /* mungehdrs needs n_ngs set */
  848. X    return mungehdrs(buffer, tfp, hdrs);    /* save or write hdr */
  849. X}
  850. X
  851. X/*
  852. X * --- header parsing and remembering starts here ---
  853. X */
  854. X
  855. X/*
  856. X * Reset internal state of header parser.
  857. X * (Empty the stomach of partially-digested headers.  Waarrrgggh!)
  858. X */
  859. Xhdrwretch()
  860. X{
  861. X    hpsp->prevvalp = NULL;
  862. X    hpsp->prevhist = NO;
  863. X    hpsp->nextcont = NO;
  864. X}
  865. X
  866. X/*
  867. X * Parse RFC822/850 header into "hdrs".  Retain significant values.
  868. X * Assumes ishdr has been called first.
  869. X */
  870. Xeatheaders(hdrs, line)
  871. Xregister struct headers *hdrs;
  872. Xregister char *line;
  873. X{
  874. X    /*
  875. X     * One would really like to use a loop through a structure here,
  876. X     * but it's hard because one can't initialise a static struct
  877. X     * with e.g. &hdrs->h_path.
  878. X     */
  879. X    if (!contin(line) &&
  880. X        !hdrmatch(line, pathnm, STRLEN(pathnm), &hdrs->h_path) &&
  881. X        !hdrmatch(line, msgnm,  STRLEN(msgnm),  &hdrs->h_msgid) &&
  882. X        !hdrmatch(line, artidnm,STRLEN(artidnm),&hdrs->h_artid) &&    /* obs. */
  883. X        !hdrmatch(line, subjnm, STRLEN(subjnm), &hdrs->h_subj) &&
  884. X        !hdrmatch(line, ngsnm,  STRLEN(ngsnm),  &hdrs->h_ngs) &&
  885. X        !hdrmatch(line, distrnm,STRLEN(distrnm),&hdrs->h_distr) &&
  886. X        !hdrmatch(line, appnm,  STRLEN(appnm),  &hdrs->h_approved) &&
  887. X        !hdrmatch(line, ctlnm,  STRLEN(ctlnm),  &hdrs->h_ctlcmd)) {
  888. X        static char *dummy = NULL;
  889. X
  890. X        /*
  891. X         * silly header - just set hpsp->prevvalp for contin()
  892. X         * so that unrecognised headers may be continued.
  893. X         */
  894. X        if (dummy != NULL)
  895. X            free(dummy);
  896. X        dummy = strsave("");    /* may be realloced in contin() */
  897. X        hpsp->prevvalp = &dummy;    /* ditto */
  898. X    }
  899. X    hpsp->nextcont = hpsp->newnextcont;    /* set nextcont for next line */
  900. X}
  901. X
  902. Xhdrdeflt(hdrs)                /* default missing header values */
  903. Xregister struct headers *hdrs;
  904. X{
  905. X    /*
  906. X     * if strsave ever returns NULL on failure, instead of exiting,
  907. X     * then the following calls need to check for failure.
  908. X     */
  909. X    if (hdrs->h_ngs == NULL)
  910. X        hdrs->h_ngs = strsave(JUNK);
  911. X    if (hdrs->h_msgid == NULL && hdrs->h_artid != NULL)
  912. X        hdrs->h_msgid = strsave(hdrs->h_artid);
  913. X    if (hdrs->h_msgid == NULL)
  914. X        hdrs->h_msgid = strsave(DEFMSGID);
  915. X    if (hdrs->h_expiry == NULL)
  916. X        hdrs->h_expiry = strsave("-");    /* - means "default" */
  917. X    if (hdrs->h_subj == NULL)
  918. X        hdrs->h_subj = strsave("");
  919. X
  920. X    /*
  921. X     * Control message backwards compatibility, and I mean *backwards*.
  922. X     * We're talking stone age here; we're probably talking A news: if
  923. X     * no Control: header exists and the newsgroup matches all.all.ctl,
  924. X     * use the Subject: as the control message.
  925. X     *
  926. X     * Since RFC 850 is vague on the subject, we will henceforth
  927. X     * internally (but not on disk), treat the Newsgroup: value as
  928. X     * foo.bar, not foo.bar.ctl.  This simplifies the rest of
  929. X     * processing somewhat.
  930. X     */
  931. X    if (hdrs->h_ctlcmd == NULL && oldctl(hdrs)) {
  932. X        hdrs->h_ctlcmd = strsave(hdrs->h_subj);
  933. X        hdrs->h_ngs[strlen(hdrs->h_ngs) - STRLEN(".ctl")] = '\0';
  934. X    }
  935. X
  936. X    if (hdrs->h_ctlcmd != NULL)        /* control message */
  937. X        hdrs->h_octlchked = NO;        /* invalidate old comparison */
  938. X    if (hdrs->h_distr == NULL)
  939. X        hdrs->h_distr = strsave(DEFDIST);
  940. X}
  941. X
  942. Xstatic int
  943. Xiscontin(s)                /* is s an RFC 822 header continuation? */
  944. Xregister char *s;
  945. X{
  946. X    return hpsp->nextcont || hpsp->prevhist && iswhite(*s);
  947. X}
  948. X
  949. Xint
  950. Xishdr(s)                /* is s an RFC 822 header line? */
  951. Xchar *s;
  952. X{
  953. X    register char *cp = s;
  954. X
  955. X    if (iscontin(s))
  956. X        hpsp->prevhist = YES;
  957. X    else {
  958. X        register int c;
  959. X
  960. X        /* look for first of NUL, whitespace, colon */
  961. X        while ((c = *cp) != '\0' && !(isascii(c) && isspace(c)) &&
  962. X            c != ':')
  963. X            ++cp;
  964. X        hpsp->prevhist = (c == ':' && cp > s);    /* colon not 1st char */
  965. X    }
  966. X    /*
  967. X     * If this is a header line and there is no trailing newline,
  968. X     * assume fgets couldn't fit a very long header into the buffer
  969. X     * for header lines, so the next line fgets sees must be a
  970. X     * continuation of this line.
  971. X     */
  972. X    if (hpsp->prevhist) {
  973. X#ifndef DIRTYHDRCONT
  974. X        INDEX(cp, '\n', cp);
  975. X        hpsp->newnextcont = (cp == NULL);    /* no \n -> continue */
  976. X#else    /* DIRTYHDRCONT */
  977. X        hpsp->newnextcont =
  978. X            *hpsp->endlnp != '\0' && *hpsp->endlnp != '\n';
  979. X#endif    /* DIRTYHDRCONT */
  980. X    } else
  981. X        hpsp->newnextcont = NO;
  982. X    return hpsp->prevhist;
  983. X}
  984. X
  985. Xint
  986. Xcontin(line)        /* append continuation value to old value */
  987. Xchar *line;
  988. X{
  989. X    /*
  990. X     * If there is a previous header value and this line starts
  991. X     * with whitespace other than a newline, realloc *hpsp->prevvalp
  992. X     * with enough space for the old value, the new value and a NUL.
  993. X     * Then append the new value.
  994. X     */
  995. X    if (hpsp->prevvalp != NULL && iscontin(line)) {
  996. X        char *valp = /* skipsp */ (line);    /* continuation value */
  997. X
  998. X        /* hpsp->prevvalp was previously set in hdrmatch() or eatheaders() */
  999. X        *hpsp->prevvalp = realloc(*hpsp->prevvalp,
  1000. X            (unsigned)strlen(*hpsp->prevvalp) + strlen(valp) + 1);
  1001. X        if (*hpsp->prevvalp == NULL)
  1002. X            warning("realloc failed in contin", "");
  1003. X        else {
  1004. X            (void) strcat(*hpsp->prevvalp, valp);
  1005. X            trim(*hpsp->prevvalp);    /* remove trailing newline */
  1006. X        }
  1007. X        return YES;
  1008. X    } else
  1009. X        return NO;
  1010. X}
  1011. X
  1012. X/*
  1013. X * Match line with keyword (return truth value).
  1014. X * If it matches, store the value in *malloc'ed memory* (N.B.)
  1015. X * and set *ptrp to point there.  freeheader() will free this memory.
  1016. X */
  1017. Xint
  1018. Xhdrmatch(line, keyword, keylen, ptrp)
  1019. Xregister char *line, *keyword;
  1020. Xregister int keylen;            /* an optimisation */
  1021. Xregister char **ptrp;            /* make it point at valuep */
  1022. X{
  1023. X#ifdef notdef
  1024. X    register int keylen = strlen(keyword);    /* the slower way */
  1025. X#endif
  1026. X    register int match = STREQN(line, keyword, keylen);
  1027. X
  1028. X    if (match && *ptrp != NULL)    /* value already set */
  1029. X        free(*ptrp);        /* return storage */
  1030. X    if (match && (*ptrp = strsave(skipsp(&line[keylen]))) != NULL) {
  1031. X        trim(*ptrp);        /* remove trailing new line */
  1032. X        hpsp->prevvalp = ptrp;    /* for contin() */
  1033. X    }
  1034. X    return match;
  1035. X}
  1036. X
  1037. Xfreeheaders(hdrs)        /* free (assumed) malloced storage */
  1038. Xregister struct headers *hdrs;
  1039. X{
  1040. X    nnfree(&hdrs->h_subj);
  1041. X    nnfree(&hdrs->h_ngs);
  1042. X    nnfree(&hdrs->h_distr);
  1043. X    nnfree(&hdrs->h_ctlcmd);
  1044. X    nnfree(&hdrs->h_approved);
  1045. X    nnfree(&hdrs->h_msgid);
  1046. X    nnfree(&hdrs->h_artid);
  1047. X    nnfree(&hdrs->h_expiry);
  1048. X    nnfree(&hdrs->h_path);
  1049. X}
  1050. X
  1051. Xnnfree(mempp)                /* free non-null pointer's memory */
  1052. Xregister char **mempp;            /* pointer to malloc'ed ptr. */
  1053. X{
  1054. X    if (*mempp != NULL) {
  1055. X        free(*mempp);
  1056. X        *mempp = NULL;
  1057. X    }
  1058. X}
  1059. X
  1060. Xint
  1061. Xemitxref(tf, hdrs)        /* splat out an Xref: line from Newsgroups: */
  1062. Xregister FILE *tf;
  1063. Xstruct headers *hdrs;
  1064. X{
  1065. X    register char *slashp;
  1066. X    int status = ST_OKAY;
  1067. X    char xrefs[MAXLINE];
  1068. X
  1069. X    if (!hdrs->h_xref) {        /* this article has no Xref: yet */
  1070. X        hdrs->h_xref = YES;
  1071. X        (void) strcpy(xrefs, hdrs->h_files);
  1072. X        /* turn slashes into colons for the benefit of rn */
  1073. X        for (slashp = xrefs; (slashp = index(slashp, FNDELIM)) != NULL; )
  1074. X            *slashp++ = ':';
  1075. X        if (fprintf(tf, "%s %s %s\n", xrefnm, hostname(), xrefs) == EOF)
  1076. X            status = fulldisk(status|ST_DROPPED,
  1077. X                (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1078. X    }
  1079. X    return status;
  1080. X}
  1081. X
  1082. X/*
  1083. X * --- header munging (copying) starts here ---
  1084. X */
  1085. X
  1086. X/*
  1087. X * Copy headers and munge a few.  Assumes eatheaders has been called.
  1088. X *
  1089. X * Don't copy Date-Received nor *-Version nor Xref.
  1090. X * Prepend hostname! to Path: value.
  1091. X * Recognise Newsgroups: and if more than one, generate Xref: &
  1092. X * leave holes for the article numbers - fileart will fill them in.
  1093. X * (Make rn look in history instead?)
  1094. X *
  1095. X * (Header munging should be a felony.  When they make me dictator,
  1096. X * it will be: punishable by having to use 4.2BSD networking.)
  1097. X *
  1098. X * New strategy: pile up headers into a static buffer until
  1099. X * end of buffer (next line might not fit) [checked in hdrsave()]; end of
  1100. X * headers, file or byte count [checked in cparttofp].
  1101. X * During reading, discard swill headers.  Path: is munged on output.
  1102. X * Copy (save) or discard header lines.
  1103. X */
  1104. Xint
  1105. Xmungehdrs(buffer, tfp, hdrs)
  1106. Xregister char *buffer;
  1107. Xregister FILE **tfp;
  1108. Xstruct headers *hdrs;
  1109. X{
  1110. X    struct vilesthdrs {
  1111. X        char *vh_name;
  1112. X        unsigned vh_len;
  1113. X    };
  1114. X    register struct vilesthdrs *vhp;
  1115. X    static struct vilesthdrs vilest[] = {
  1116. X        datercvnm,    STRLEN(datercvnm),
  1117. X        rcvnm,        STRLEN(rcvnm),
  1118. X        rlyversnm,    STRLEN(rlyversnm),
  1119. X        postversnm,    STRLEN(postversnm),
  1120. X        xrefnm,        STRLEN(xrefnm),
  1121. X        NULL,        0
  1122. X    };
  1123. X
  1124. X    if (debug)
  1125. X        (void) fputs(buffer, stderr);
  1126. X    /*
  1127. X     * Toss the most vile of the trash headers.
  1128. X     * In an ideal world, this code wouldn't exist.
  1129. X     */
  1130. X    for (vhp = vilest; vhp->vh_name != NULL; vhp++)
  1131. X        if (STREQN(buffer, vhp->vh_name, (int)vhp->vh_len))
  1132. X            return ST_OKAY;
  1133. X    /* wasn't vile; save it.  *tfp may be NULL.  Be Prepared. */
  1134. X    return hdrsave(buffer, hdrs, tfp);    /* may set *tfp */
  1135. X}
  1136. X
  1137. X/*
  1138. X * If headers already dumped (hdrs->h_filed), just write to *tfp.
  1139. X * If there is room, stash "hdr" away until Newsgroups: is seen,
  1140. X * then open the first article link (on *tfp)
  1141. X * and dump the saved headers to it.
  1142. X * Copy into hdrs->h_accum (TODO: read in directly, iff high on profile).
  1143. X * TODO: may want an end-of-accum pointer for speed, iff high on profile.
  1144. X */
  1145. Xint
  1146. Xhdrsave(hdr, hdrs, tfp)
  1147. Xchar *hdr;
  1148. Xregister struct headers *hdrs;
  1149. XFILE **tfp;
  1150. X{
  1151. X    int status = ST_OKAY;
  1152. X    unsigned hdrlen = strlen(hdr);
  1153. X
  1154. X    if (hdrs->h_filed)            /* *tfp != NULL */
  1155. X        return emithdr(hdrs, hdr, *tfp);
  1156. X    if (hdrs->h_accum == NULL) {
  1157. X        hdrs->h_accum = hpsp->hdraccum;    /* primitive storage allocation */
  1158. X        hdrs->h_accum[0] = '\0';
  1159. X        hdrs->h_bytesleft = sizeof hpsp->hdraccum;
  1160. X    }
  1161. X    if (hdrs->h_bytesleft > hdrlen) {    /* it fits! */
  1162. X        (void) strcat(hdrs->h_accum, hdr);    /* whomp it on the end */
  1163. X        hdrs->h_bytesleft -= hdrlen;
  1164. X    } else {                /* no room; barf out headers */
  1165. X        status |= hdrdump(tfp, hdrs, NO);    /* don't trigger fileart */
  1166. X        if (*tfp != NULL)
  1167. X            status |= emithdr(hdrs, hdr, *tfp);
  1168. X    }
  1169. X    return status;
  1170. X}
  1171. X
  1172. Xstatic int
  1173. Xemithdr(hdrs, hdr, tf)    /* munge Path: else just dump the header (hdr) */
  1174. Xregister struct headers *hdrs;
  1175. Xchar *hdr;
  1176. XFILE *tf;
  1177. X{
  1178. X    register int status = ST_OKAY;
  1179. X
  1180. X    if (STREQN(hdr, pathnm, STRLEN(pathnm))) {    /* Path: */
  1181. X        register int hdrbytes;
  1182. X        register char *oldpath;
  1183. X
  1184. X        oldpath = skipsp(&hdr[STRLEN(pathnm)]);
  1185. X        hdrbytes = fprintf(tf, "%s %s!", pathnm, hostname());
  1186. X        if (hdrbytes == EOF || fputs(oldpath, tf) == EOF)
  1187. X            status = fulldisk(status|ST_DROPPED,
  1188. X                (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1189. X        else
  1190. X            hdrs->h_charswritten += hdrbytes + strlen(oldpath);
  1191. X    } else {                    /* ordinary header */
  1192. X        if (fputs(hdr, tf) == EOF)
  1193. X            status = fulldisk(status|ST_DROPPED,
  1194. X                (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1195. X        else
  1196. X            hdrs->h_charswritten += strlen(hdr);
  1197. X    }
  1198. X    return status;
  1199. X}
  1200. X
  1201. X/*
  1202. X * Barf out headers after opening on *tfp either a temporary file (using
  1203. X * mktemp(3)) or the first article link, based on the h_ngs & nxtartnum();
  1204. X * set h_tmpf to which ever name is opened.  Modify Path: value on the way.
  1205. X */
  1206. Xint
  1207. Xhdrdump(tfp, hdrs, allhdrsseen)
  1208. XFILE **tfp;
  1209. Xregister struct headers *hdrs;
  1210. Xint allhdrsseen;
  1211. X{
  1212. X    int status = ST_OKAY;
  1213. X
  1214. X    if (hdrs->h_filed)
  1215. X        return status;
  1216. X    /*
  1217. X     * If all headers were seen & the group was not an old backward-
  1218. X     * compatible control group (which won't exist), then open the
  1219. X     * first link, link to the rest, generate Xref:, else open a
  1220. X     * temporary name and write the article there
  1221. X     * (it will get filed later in insart()).
  1222. X     */
  1223. X    if (allhdrsseen && hdrs->h_ngs != NULL && !oldctl(hdrs))
  1224. X        status |= fileart(hdrs, tfp, 1);
  1225. X    else {
  1226. X        (void) strcpy(hdrs->h_tmpf, SPOOLTMP);
  1227. X        (void) mktemp(hdrs->h_tmpf);    /* make a temporary name */
  1228. X        hdrs->h_unlink = 1;        /* unlink it when done */
  1229. X        if ((*tfp = fopen(hdrs->h_tmpf, "w")) == NULL) {
  1230. X            warning("can't open temporary name `%s'", hdrs->h_tmpf);
  1231. X            status |= ST_DROPPED;
  1232. X        }
  1233. X    }
  1234. X    if (*tfp != NULL) {
  1235. X        register char *line, *nlp;
  1236. X        register int saved;
  1237. X
  1238. X        /* this is a deadly tedious job and I really should automate it */
  1239. X        for (line = hdrs->h_accum; line != NULL && line[0] != '\0';
  1240. X             line = nlp) {
  1241. X                 /*
  1242. X                  * Could this call on INDEX be eliminated without
  1243. X                  * restricting the number of header lines?
  1244. X                  */
  1245. X                 INDEX(line, '\n', nlp);
  1246. X            if (nlp != NULL) {
  1247. X                ++nlp;        /* byte after \n is NUL or text */
  1248. X                saved = *nlp;
  1249. X                *nlp = '\0';    /* will be restored below */
  1250. X            }
  1251. X            if (emithdr(hdrs, line, *tfp) == EOF)    /* dump saved headers */
  1252. X                status = fulldisk(status|ST_DROPPED,
  1253. X                    (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1254. X                 if (nlp != NULL)
  1255. X                     *nlp = saved;    /* restore  */
  1256. X        }
  1257. X    }
  1258. X#ifdef notdef
  1259. X    hdrs->h_accum = NULL;        /* primitive memory deallocation */
  1260. X#endif
  1261. X    return status;
  1262. X}
  1263. END_OF_FILE
  1264. if test 18247 -ne `wc -c <'rnews/headers.c'`; then
  1265.     echo shar: \"'rnews/headers.c'\" unpacked with wrong size!
  1266. fi
  1267. # end of 'rnews/headers.c'
  1268. fi
  1269. echo shar: End of archive 12 \(of 14\).
  1270. ##  End of shell archive.
  1271. exit 0
  1272.